enum Direction {
  Up = 0,
  Right = 1,
  Down = 2,
  Left = 3
}

export class InputManager {
  events: any = {};
  constructor() {
    this.addKeyboadListener();
    this.addSwipeListener();
  }
  on(event: string, callback: any) {
    // 给事件绑定回调函数
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  }

  emit(event: string, data?: any) {
    const callbacks = this.events[event];
    if (callbacks) {
      callbacks.forEach((callback: (arg: any) => void) => {
        callback(data);
      });
    }
  }
  addKeyboadListener() {
    const self = this;

    const map: any = {
      38: Direction.Up, // Up
      39: Direction.Right, // Right
      40: Direction.Down, // Down
      37: Direction.Left, // Left
      75: Direction.Up, // Vim up
      76: Direction.Right, // Vim right
      74: Direction.Down, // Vim down
      72: Direction.Left, // Vim left
      87: Direction.Up, // W
      68: Direction.Right, // D
      83: Direction.Down, // S
      65: Direction.Left  // A
    };

    // Respond to direction keys
    document.addEventListener("keydown", function (event: any) {
      const modifiers = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
      const mapped = map[event.keyCode];

      if (!modifiers) {
        if (mapped !== undefined) {
          event.preventDefault();
          self.emit("move", mapped);
        }
      }
    });
  }

  addSwipeListener() {
    const self = this;

    let eventTouchstart;
    let eventTouchmove;
    let eventTouchend;
    // @ts-ignore
    if (window.navigator.msPointerEnabled) {
      eventTouchstart = "MSPointerDown";
      eventTouchmove = "MSPointerMove";
      eventTouchend = "MSPointerUp";
    } else {
      eventTouchstart = "touchstart";
      eventTouchmove = "touchmove";
      eventTouchend = "touchend";
    }
    // Respond to swipe events
    let touchStartClientX: number, touchStartClientY: number;
    const gameContainer = document.getElementById("game-container");

    gameContainer?.addEventListener(eventTouchstart, function (event: any) {
      event.preventDefault();
      // @ts-ignore
      if ((!window.navigator.msPointerEnabled && event.touches.length > 1) ||
        event.targetTouches.length > 1) {
        return; // Ignore if touching with more than 1 finger
      }
      // @ts-ignore
      if (window.navigator.msPointerEnabled) {
        touchStartClientX = event.pageX;
        touchStartClientY = event.pageY;
      } else {
        touchStartClientX = event.touches[0].clientX;
        touchStartClientY = event.touches[0].clientY;
      }

      event.preventDefault();
    });

    gameContainer?.addEventListener(eventTouchmove, function (event: any) {
      event.preventDefault();
    });

    gameContainer?.addEventListener(eventTouchend, function (event: any) {
      event.preventDefault();
      // @ts-ignore
      if ((!window.navigator.msPointerEnabled && event.touches.length > 0) ||
        event.targetTouches.length > 0) {
        return; // Ignore if still touching with one or more fingers
      }

      let touchEndClientX, touchEndClientY;
      // @ts-ignore
      if (window.navigator.msPointerEnabled) {
        touchEndClientX = event.pageX;
        touchEndClientY = event.pageY;
      } else {
        touchEndClientX = event.changedTouches[0].clientX;
        touchEndClientY = event.changedTouches[0].clientY;
      }

      const dx = touchEndClientX - touchStartClientX;
      const absDx = Math.abs(dx); //水平方向绝对值

      const dy = touchEndClientY - touchStartClientY;
      const absDy = Math.abs(dy);

      if (Math.max(absDx, absDy) > 10) {
        // 判断滑动距离 > 10表示有意滑动
        // (right : left) : (down : up)
        self.emit("move", absDx > absDy ? (dx > 0 ? Direction.Right : Direction.Left) : (dy > 0 ? Direction.Down : Direction.Up));
      }
    });
  }

  keepPlaying(event: any) {
    event.preventDefault();
    this.emit("keepPlaying");
  }
}